﻿using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Feature.Services.Bulbs;
using JetBrains.ReSharper.Feature.Services.CSharp.Bulbs;
using JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots;
using JetBrains.ReSharper.Intentions.Extensibility;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Tree;
using JetBrains.TextControl;
using JetBrains.Util;
using MugenMvvmToolkit.ReSharper.Infrastructure;
using MugenMvvmToolkit.ReSharper.PluginModels;

namespace MugenMvvmToolkit.ReSharper.ViewModels.ContextActions
{
    [ContextAction(Name = "InheritFromViewModelAction", Group = "C#", Priority = -20)]
    public class InheritFromViewModelAction : ContextActionImplBase
    {
        #region Fields

        private IClassDeclaration _currentClassDeclaration;

        #endregion

        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="InheritFromViewModelAction" /> class.
        /// </summary>
        public InheritFromViewModelAction([NotNull] ICSharpContextActionDataProvider provider)
            : base(provider)
        {
        }

        #endregion

        #region Implementation of IContextAction

        /// <summary>
        ///     Check if this action is available at the constructed context.
        ///     Actions could store precalculated info in <paramref name="cache" /> to share it between different actions
        /// </summary>
        /// <returns>
        ///     true if this bulb action is available, false otherwise.
        /// </returns>
        public override bool IsAvailable(IUserDataHolder cache)
        {
            if (Provider.SelectedElement == null)
                return false;
            _currentClassDeclaration = Provider.SelectedElement.Parent as IClassDeclaration;
            if (_currentClassDeclaration == null || _currentClassDeclaration.IsStaticEx() ||
                _currentClassDeclaration.HasBaseClass())
                return false;

            Actions = new List<IBulbAction>();
            foreach (ViewModelMetaModel viewModelType in
                TypeProvider.GetBaseViewModelTypes()
                    .Where(type => type.ViewModelType.IsResolved)
                    .OrderByDescending(model => model.Priority))
            {
                IDeclaredType declaredType = viewModelType.ViewModelType;
                Actions.Add(new DelegateBulbAction((solution, control) => Execute(solution, declaredType),
                    string.Format(UiResources.InheritFromViewModelFormat, viewModelType.Name)));
            }
            return Actions.Count != 0;
        }

        private Action<ITextControl> Execute(ISolution solution, IDeclaredType type)
        {
            bool isGeneric;
            type = Extensions.UpdateType(type, TypeProvider.Object, out isGeneric);
            ITypeElement typeElement = type.GetTypeElement();
            _currentClassDeclaration.SetSuperClass(type);
            if (!isGeneric || typeElement == null)
                return null;

            return control =>
            {
                IUserDeclaredTypeUsage typeUsage = _currentClassDeclaration
                    .SuperTypeUsageNodes
                    .OfType<IUserDeclaredTypeUsage>()
                    .SingleOrDefault(
                        usage =>
                            usage.TypeName.ShortName == type.GetClrName().ShortName &&
                            !usage.TypeName.TypeArgumentList.IsEmpty() &&
                            usage.TypeName.TypeArgumentList.TypeArgumentNodes.Count == typeElement.TypeParameters.Count);
                if (typeUsage == null)
                    return;
                HotspotInfo[] hotspotInfos = Extensions
                    .GetGenericTypesHotspots(typeUsage.TypeName.TypeArgumentList.TypeArgumentNodes, Provider.PsiModule, Provider.PsiFile.Language);
                LiveTemplatesManager.TryExecuteHotspotDefault(solution, control, hotspotInfos);
            };
        }

        #endregion
    }
}